/*
* Cvar.java
* Copyright (C) 2003
* 
* $Id: Cvar.java,v 1.9 2005/12/27 21:02:30 salomo Exp $
*/
/*
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
using System;
using Defines = Suake2.UI.Defines;
using Globals = Suake2.UI.Globals;
using Cmd = Suake2.UI.game.Cmd;
using Info = Suake2.UI.game.Info;
using cvar_t = Suake2.UI.game.cvar_t;
using Lib = Suake2.UI.util.Lib;
namespace Suake2.UI.qcommon
{
	
	/// <summary> Cvar implements console variables. The original code is located in cvar.c</summary>
	public class Cvar:Globals
	{
		public class AnonymousClassxcommand_t:xcommand_t
		{
			public override void  execute()
			{
				int c;
				int flags;
				
				c = Cmd.Argc();
				if (c != 3 && c != 4)
				{
					Com.Printf("usage: set <variable> <value> [u / s]\n");
					return ;
				}
				
				if (c == 4)
				{
					if (Cmd.Argv(3).Equals("u"))
						flags = Suake2.UI.Defines.CVAR_USERINFO;
					else if (Cmd.Argv(3).Equals("s"))
						flags = Suake2.UI.Defines.CVAR_SERVERINFO;
					else
					{
						Com.Printf("flags can only be 'u' or 's'\n");
						return ;
					}
					Cvar.FullSet(Cmd.Argv(1), Cmd.Argv(2), flags);
				}
				else
					Cvar.Set(Cmd.Argv(1), Cmd.Argv(2));
			}
		}
		public class AnonymousClassxcommand_t1:xcommand_t
		{
			public override void  execute()
			{
				cvar_t var;
				int i;
				
				i = 0;
				for (var = Globals.cvar_vars; var != null; var = var.next, i++)
				{
					if ((var.flags & jake2.Defines.CVAR_ARCHIVE) != 0)
						Com.Printf("*");
					else
						Com.Printf(" ");
					if ((var.flags & jake2.Defines.CVAR_USERINFO) != 0)
						Com.Printf("U");
					else
						Com.Printf(" ");
					if ((var.flags & jake2.Defines.CVAR_SERVERINFO) != 0)
						Com.Printf("S");
					else
						Com.Printf(" ");
					if ((var.flags & jake2.Defines.CVAR_NOSET) != 0)
						Com.Printf("-");
					else if ((var.flags & jake2.Defines.CVAR_LATCH) != 0)
						Com.Printf("L");
					else
						Com.Printf(" ");
					Com.Printf(" " + var.name + " \"" + var.string_Renamed + "\"\n");
				}
				Com.Printf(i + " cvars\n");
			}
		}
		
		/// <param name="var_name">
		/// </param>
		/// <param name="var_value">
		/// </param>
		/// <param name="flags">
		/// </param>
		/// <returns>
		/// </returns>
		public static cvar_t Get(System.String var_name, System.String var_value, int flags)
		{
			cvar_t var;
			
			if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0)
			{
				if (!InfoValidate(var_name))
				{
					Com.Printf("invalid info cvar name\n");
					return null;
				}
			}
			
			var = Cvar.FindVar(var_name);
			if (var != null)
			{
				var.flags |= flags;
				return var;
			}
			
			if (var_value == null)
				return null;
			
			if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0)
			{
				if (!InfoValidate(var_value))
				{
					Com.Printf("invalid info cvar value\n");
					return null;
				}
			}
			var = new cvar_t();
			var.name = new System.Text.StringBuilder(var_name).ToString();
			var.string_Renamed = new System.Text.StringBuilder(var_value).ToString();
			var.modified = true;
			// handles atof(var.string)
			try
			{
				var.value_Renamed = System.Single.Parse(var.string_Renamed);
			}
			catch (System.FormatException e)
			{
				var.value_Renamed = 0.0f;
			}
			// link the variable in
			var.next = Globals.cvar_vars;
			Globals.cvar_vars = var;
			
			var.flags = flags;
			
			return var;
		}
		
		internal static void  Init()
		{
			Cmd.AddCommand("set", Set_f);
			Cmd.AddCommand("cvarlist", List_f);
		}
		
		public static System.String VariableString(System.String var_name)
		{
			cvar_t var;
			var = FindVar(var_name);
			return (var == null)?"":var.string_Renamed;
		}
		
		internal static cvar_t FindVar(System.String var_name)
		{
			cvar_t var;
			
			for (var = Globals.cvar_vars; var != null; var = var.next)
			{
				if (var_name.Equals(var.name))
					return var;
			}
			
			return null;
		}
		
		/// <summary> Creates a variable if not found and sets their value, the parsed float value and their flags.</summary>
		public static cvar_t FullSet(System.String var_name, System.String value_Renamed, int flags)
		{
			cvar_t var;
			
			var = Cvar.FindVar(var_name);
			if (null == var)
			{
				// create it
				return Cvar.Get(var_name, value_Renamed, flags);
			}
			
			var.modified = true;
			
			if ((var.flags & CVAR_USERINFO) != 0)
				Globals.userinfo_modified = true; // transmit at next oportunity
			
			var.string_Renamed = value_Renamed;
			try
			{
				var.value_Renamed = System.Single.Parse(var.string_Renamed);
			}
			catch (System.Exception e)
			{
				var.value_Renamed = 0.0f;
			}
			
			var.flags = flags;
			
			return var;
		}
		
		/// <summary> Sets the value of the variable without forcing. </summary>
		public static cvar_t Set(System.String var_name, System.String value_Renamed)
		{
			return Set2(var_name, value_Renamed, false);
		}
		
		/// <summary> Sets the value of the variable with forcing. </summary>
		public static cvar_t ForceSet(System.String var_name, System.String value_Renamed)
		{
			return Cvar.Set2(var_name, value_Renamed, true);
		}
		
		/// <summary> Gereric set function, sets the value of the variable, with forcing its even possible to 
		/// override the variables write protection. 
		/// </summary>
		internal static cvar_t Set2(System.String var_name, System.String value_Renamed, bool force)
		{
			
			cvar_t var = Cvar.FindVar(var_name);
			if (var == null)
			{
				// create it
				return Cvar.Get(var_name, value_Renamed, 0);
			}
			
			if ((var.flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0)
			{
				if (!InfoValidate(value_Renamed))
				{
					Com.Printf("invalid info cvar value\n");
					return var;
				}
			}
			
			if (!force)
			{
				if ((var.flags & CVAR_NOSET) != 0)
				{
					Com.Printf(var_name + " is write protected.\n");
					return var;
				}
				
				if ((var.flags & CVAR_LATCH) != 0)
				{
					if (var.latched_string != null)
					{
						if (value_Renamed.Equals(var.latched_string))
							return var;
						var.latched_string = null;
					}
					else
					{
						if (value_Renamed.Equals(var.string_Renamed))
							return var;
					}
					
					if (Globals.server_state != 0)
					{
						Com.Printf(var_name + " will be changed for next game.\n");
						var.latched_string = value_Renamed;
					}
					else
					{
						var.string_Renamed = value_Renamed;
						try
						{
							var.value_Renamed = System.Single.Parse(var.string_Renamed);
						}
						catch (System.Exception e)
						{
							var.value_Renamed = 0.0f;
						}
						if (var.name.Equals("game"))
						{
							FS.SetGamedir(var.string_Renamed);
							FS.ExecAutoexec();
						}
					}
					return var;
				}
			}
			else
			{
				if (var.latched_string != null)
				{
					var.latched_string = null;
				}
			}
			
			if (value_Renamed.Equals(var.string_Renamed))
				return var; // not changed
			
			var.modified = true;
			
			if ((var.flags & CVAR_USERINFO) != 0)
				Globals.userinfo_modified = true; // transmit at next oportunity
			
			var.string_Renamed = value_Renamed;
			try
			{
				var.value_Renamed = System.Single.Parse(var.string_Renamed);
			}
			catch (System.Exception e)
			{
				var.value_Renamed = 0.0f;
			}
			
			return var;
		}
		
		/// <summary> Set command, sets variables.</summary>
		
		//UPGRADE_NOTE: The initialization of  'Set_f' was moved to static method 'jake2.qcommon.Cvar'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		internal static xcommand_t Set_f;
		
		/// <summary> List command, lists all available commands.</summary>
		//UPGRADE_NOTE: The initialization of  'List_f' was moved to static method 'jake2.qcommon.Cvar'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		internal static xcommand_t List_f;
		
		
		
		/// <summary> Sets a float value of a variable.
		/// 
		/// The overloading is very important, there was a problem with 
		/// networt "rate" string --> 10000 became "10000.0" and that wasn't right.
		/// </summary>
		public static void  SetValue(System.String var_name, int value_Renamed)
		{
			Cvar.Set(var_name, "" + value_Renamed);
		}
		
		public static void  SetValue(System.String var_name, float value_Renamed)
		{
			//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
			if (value_Renamed == (int) value_Renamed)
			{
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				Cvar.Set(var_name, "" + (int) value_Renamed);
			}
			else
			{
				Cvar.Set(var_name, "" + value_Renamed);
			}
		}
		
		/// <summary> Returns the float value of a variable.</summary>
		public static float VariableValue(System.String var_name)
		{
			cvar_t var = Cvar.FindVar(var_name);
			if (var == null)
				return 0;
			float val = 0.0f;
			try
			{
				val = System.Single.Parse(var.string_Renamed);
			}
			catch (System.Exception e)
			{
			}
			return val;
		}
		
		/// <summary> Handles variable inspection and changing from the console.</summary>
		public static bool Command()
		{
			cvar_t v;
			
			// check variables
			v = Cvar.FindVar(Cmd.Argv(0));
			if (v == null)
				return false;
			
			// perform a variable print or set
			if (Cmd.Argc() == 1)
			{
				Com.Printf("\"" + v.name + "\" is \"" + v.string_Renamed + "\"\n");
				return true;
			}
			
			Cvar.Set(v.name, Cmd.Argv(1));
			return true;
		}
		
		public static System.String BitInfo(int bit)
		{
			System.String info;
			cvar_t var;
			
			info = "";
			
			for (var = Globals.cvar_vars; var != null; var = var.next)
			{
				if ((var.flags & bit) != 0)
					info = Info.Info_SetValueForKey(info, var.name, var.string_Renamed);
			}
			return info;
		}
		
		/// <summary> Returns an info string containing all the CVAR_SERVERINFO cvars. </summary>
		public static System.String Serverinfo()
		{
			return BitInfo(Defines.CVAR_SERVERINFO);
		}
		
		
		/// <summary> Any variables with latched values will be updated.</summary>
		public static void  GetLatchedVars()
		{
			cvar_t var;
			
			for (var = Globals.cvar_vars; var != null; var = var.next)
			{
				if (var.latched_string == null || var.latched_string.Length == 0)
					continue;
				var.string_Renamed = var.latched_string;
				var.latched_string = null;
				try
				{
					var.value_Renamed = System.Single.Parse(var.string_Renamed);
				}
				catch (System.FormatException e)
				{
					var.value_Renamed = 0.0f;
				}
				if (var.name.Equals("game"))
				{
					FS.SetGamedir(var.string_Renamed);
					FS.ExecAutoexec();
				}
			}
		}
		
		/// <summary> Returns an info string containing all the CVAR_USERINFO cvars.</summary>
		public static System.String Userinfo()
		{
			return BitInfo(CVAR_USERINFO);
		}
		
		/// <summary> Appends lines containing \"set vaqriable value\" for all variables
		/// with the archive flag set true. 
		/// </summary>
		
		public static void  WriteVariables(System.String path)
		{
			cvar_t var;
			//UPGRADE_TODO: Class 'java.io.RandomAccessFile' was converted to 'System.IO.FileStream' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioRandomAccessFile'"
			System.IO.FileStream f;
			System.String buffer;
			
			f = Lib.fopen(path, "rw");
			if (f == null)
				return ;
			
			try
			{
				f.Seek(f.Length, System.IO.SeekOrigin.Begin);
			}
			catch (System.IO.IOException e1)
			{
				Lib.fclose(f);
				return ;
			}
			for (var = cvar_vars; var != null; var = var.next)
			{
				if ((var.flags & CVAR_ARCHIVE) != 0)
				{
					buffer = "set " + var.name + " \"" + var.string_Renamed + "\"\n";
					try
					{
						SupportClass.RandomAccessFileSupport.WriteBytes(buffer, f);
					}
					catch (System.IO.IOException e)
					{
					}
				}
			}
			Lib.fclose(f);
		}
		
		/// <summary> Variable typing auto completition.</summary>
		public static System.Collections.ArrayList CompleteVariable(System.String partial)
		{
			
			System.Collections.ArrayList vars = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
			
			// check match
			for (cvar_t cvar = Globals.cvar_vars; cvar != null; cvar = cvar.next)
				if (cvar.name.StartsWith(partial))
					vars.Add(cvar.name);
			
			return vars;
		}
		
		/// <summary> Some characters are invalid for info strings.</summary>
		internal static bool InfoValidate(System.String s)
		{
			if (s.IndexOf("\\") != - 1)
				return false;
			if (s.IndexOf("\"") != - 1)
				return false;
			if (s.IndexOf(";") != - 1)
				return false;
			return true;
		}
		static Cvar()
		{
			Set_f = new AnonymousClassxcommand_t();
			List_f = new AnonymousClassxcommand_t1();
		}
	}
}